package com.hnjk.cbts;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.util.component.LifeCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.core.boolex.EvaluationException;

/**
 *
 * @author caihanze
 */
public class MFrame extends javax.swing.JFrame {
	private static final Logger  logger = LoggerFactory.getLogger(MFrame.class);
	
	private static SimpleAttributeSet BLUE_ATT, RED_ATT, GREEN_ATT, BLACK_ATT;
	static {
		BLUE_ATT = new SimpleAttributeSet();
		BLUE_ATT.addAttribute(StyleConstants.CharacterConstants.Foreground, new Color(0, 0, 255));
		
		RED_ATT = new SimpleAttributeSet();
		RED_ATT.addAttribute(StyleConstants.CharacterConstants.Foreground, new Color(255, 0, 0));
		
		GREEN_ATT = new SimpleAttributeSet();
		GREEN_ATT.addAttribute(StyleConstants.CharacterConstants.Foreground, new Color(0, 255, 0));
		
		BLACK_ATT = new SimpleAttributeSet();
		BLACK_ATT.addAttribute(StyleConstants.CharacterConstants.Foreground, new Color(0, 0, 0));
	}
		                    
    private javax.swing.JLabel addressLabel;
    private javax.swing.JTextField addressTextField;
    private javax.swing.JButton checkButton;
    private javax.swing.JLabel copyrightLabel;
    private javax.swing.JButton exitButton;
    private javax.swing.JLabel messageLabel;
    private javax.swing.JScrollPane messageScrollPanel;
    private javax.swing.JTextPane messageTextPanel;
    private javax.swing.JPanel operatingPanel;
    private javax.swing.JButton publishButton;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JButton stopButton;
    private JLabel statusJlabel;
    
    private static ExamServerAddressSpeaker examServerAddressSpeaker = null;

    public MFrame() {    	
        initComponents();
    }
                     
    private void initComponents() {

        operatingPanel = new javax.swing.JPanel();
        addressLabel = new javax.swing.JLabel();
        addressTextField = new javax.swing.JTextField();
        checkButton = new javax.swing.JButton();
        publishButton = new javax.swing.JButton();
        stopButton = new javax.swing.JButton();
        exitButton = new javax.swing.JButton();
        statusPanel = new javax.swing.JPanel();
        messageScrollPanel = new javax.swing.JScrollPane();
        messageTextPanel = new javax.swing.JTextPane();
        copyrightLabel = new javax.swing.JLabel();
        messageLabel = new javax.swing.JLabel();
        statusJlabel = new JLabel();

		Image img = new ImageIcon(getResource("resource/icon.png")).getImage();
		setIconImage(img);
		setTitle("机考服务器地址发布器");
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        operatingPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        addressLabel.setText("机考服务地址：");

        checkButton.setText("<html><font color=blue>检测</font></html>");
        checkButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        checkButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                checkButtonActionPerformed(evt);
            }
        });

        publishButton.setText("<html><font color=green>发布</font></html>");
        publishButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        publishButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                publishButtonActionPerformed(evt);
            }
        });

        stopButton.setText("<html><font color=red>停止</font></html>");
        stopButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });
        stopButton.setEnabled(false);

        exitButton.setText("退出");
        exitButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        exitButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitButtonActionPerformed(evt);
            }
        });
        
        statusPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        
        
        statusJlabel.setIcon(new ImageIcon(getResource("resource/stop.png")));
        statusPanel.add(statusJlabel);

        //[start] statusPanel布局
        org.jdesktop.layout.GroupLayout statusPanelLayout = new org.jdesktop.layout.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 110, Short.MAX_VALUE)
            .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(statusPanelLayout.createSequentialGroup()
                    .add(0, 0, Short.MAX_VALUE)
                    .add(statusJlabel)
                    .add(0, 0, Short.MAX_VALUE)))
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 64, Short.MAX_VALUE)
            .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(statusPanelLayout.createSequentialGroup()
                    .add(0, 0, Short.MAX_VALUE)
                    .add(statusJlabel)
                    .add(0, 0, Short.MAX_VALUE)))
        );
        //[end]

        //[start] operatingPanel布局
        org.jdesktop.layout.GroupLayout operatingPanelLayout = new org.jdesktop.layout.GroupLayout(operatingPanel);
        operatingPanel.setLayout(operatingPanelLayout);
        operatingPanelLayout.setHorizontalGroup(
            operatingPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(operatingPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(operatingPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(operatingPanelLayout.createSequentialGroup()
                        .add(checkButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 55, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                        .add(publishButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 55, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                        .add(stopButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 55, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(18, 18, 18)
                        .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 55, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(operatingPanelLayout.createSequentialGroup()
                        .add(addressLabel)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(addressTextField)))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(statusPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(28, Short.MAX_VALUE))
        );
        operatingPanelLayout.setVerticalGroup(
            operatingPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(operatingPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(operatingPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, statusPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, operatingPanelLayout.createSequentialGroup()
                        .add(operatingPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(addressLabel)
                            .add(addressTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                        .add(operatingPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(checkButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .add(publishButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .add(stopButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        //[end]

        messageLabel.setText("运行信息：");
        // 将messageTextPanel放入滚动窗格中。
        messageScrollPanel.setViewportView(messageTextPanel);

        // 公司信息
        copyrightLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        copyrightLabel.setText("广州华南教育科技发展有限公司 2018");
        copyrightLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        //[start] MFrame布局
        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(copyrightLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .add(operatingPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, messageScrollPanel)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(messageLabel)
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(7, 7, 7)
                .add(operatingPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(messageLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(messageScrollPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(copyrightLabel))
        );
        
        Toolkit kit = Toolkit.getDefaultToolkit();
		Dimension screenSize = kit.getScreenSize();
		int screenHeight = screenSize.height;
		int screenWidth = screenSize.width;
		setSize(screenWidth / 2, screenHeight / 2);
		setLocationByPlatform(true);
		//[end]

        pack();
    }  
    
    // 检测机考服务地址是否正常
    private void checkButtonActionPerformed(java.awt.event.ActionEvent evt) {   
        String examAddress = addressTextField.getText(); 
        new Thread(){
        	public void run() {
        		if(checkExamServer(examAddress)) {
        			writeToTextPanel("机考服务正常", BLUE_ATT);
            	}
        	};        	
        }.start();        	
    }
    
    /**
     * 检查机考服务是否正常，这是一个临时的写法。
     * 最终的机考服务器地址与通讯内容按后续的接口协议制定。
     * @param host
     * @return
     */
    private boolean checkExamServer(String host) {
    	if("".equals(host)){
    		 writeToTextPanel("请填写机考服务地址", RED_ATT);  		
    	} else {
    		logger.info("受检机考服务地址：{}", host);
    		try {
    			// 此处模拟与机考服务状态检测口的通讯，简单的认为访问机考服务器/status.php路径获取到ok字符串就证明机考服务正常
    			// 实际应用要根据接口的涉及修改
				InputStream inputStream = new URL("http://" + host  + "/status.php").openStream();
				String result = IOUtils.toString(inputStream, "UTF-8");
				if("ok".equals(result)) return true;
			} catch (IOException e) {
				writeToTextPanel("机考服务地址无法访问", RED_ATT);  
				e.printStackTrace();
			} 
    	}
    	return false;
    }   
    
    // 发布
    private void publishButtonActionPerformed(java.awt.event.ActionEvent evt) {                                              
    	String examServerAddress = addressTextField.getText();

    	if(checkExamServer(examServerAddress)) {  
    		// 此处做了修改，增加对事件的支持
	    	examServerAddressSpeaker = new ExamServerAddressSpeaker(examServerAddress, new HandlerListener());
	    	examServerAddressSpeaker.setServerStatusListener(new ServerStatusListener());
	    	
	    	examServerAddressSpeaker.start();
    	}    	
    }    
    
    // 停止
    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
    	if(examServerAddressSpeaker.Started()) {
    		examServerAddressSpeaker.stop();
    	}    	
    }
    
    // 程序退出
    private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {                                           
    	
    	int result = JOptionPane.showConfirmDialog(null, "确定退出吗?");
        if(result == JOptionPane.YES_OPTION) {
        	System.exit(0);
        } else if(result == JOptionPane.NO_OPTION) {
            JOptionPane.showMessageDialog(null, "那就别乱点");
        }        
    }  
    
    public JTextPane geTextPane() {
    	return this.messageTextPanel;
    }

    /**
     * 启动入口，可用，但废弃。
     * 为了log的appender可以获取界面的textpanel，将MFrame放到GUIStarter里面作为静态类启动。
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(MFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MFrame().setVisible(true);
            }
        });
    }
    
    /**
     * 格式化获取系统当前时间字符串
     * 格式: 空格yyyy-MM-dd HH:mm:ss空格
     * 
     */
    private String getCurrentTime() {
    	SimpleDateFormat sdf = new SimpleDateFormat(" yyyy-MM-dd HH:mm:ss:SSS ");
    	return sdf.format(new Date());
    }
    /**
     * 将信息放TextPanel输出
     * @param message
     * @param att
     */
    private void writeToTextPanel(String message, SimpleAttributeSet att) {
    	Document document = messageTextPanel.getDocument();
    	try {
    		document.insertString(document.getLength(), getCurrentTime()+message+"\n", att);
    		JScrollBar jscrollBar = messageScrollPanel.getVerticalScrollBar();
    	    if (jscrollBar != null)
    	        jscrollBar.setValue(jscrollBar.getMaximum());
    	} catch (BadLocationException e) {
			//
		}    	
	}
    
    private URL getResource(String filename) {
    	return this.getClass().getClassLoader().getResource(filename);
    }
  
    
    /**
     * 用于监听jetty server状态的监听器
     * 因为要修改GUI界面，所以做成内部类。
     * @author caihanze
     *
     */
    class ServerStatusListener implements LifeCycle.Listener {

		@Override
		public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) {
			writeToTextPanel("机考服务地址发布器启动失败", RED_ATT);	
			
		}

		@Override
		public void lifeCycleStarted(LifeCycle arg0) {
			examServerAddressSpeaker.setStarted(true);
			statusJlabel.setIcon(new ImageIcon(getResource("resource/running.png")));
			statusPanel.setToolTipText("运行中");
	    	publishButton.setEnabled(false);
	    	stopButton.setEnabled(true);
	    	writeToTextPanel("机考服务地址发布器已启动", GREEN_ATT);			
		}

		@Override
		public void lifeCycleStarting(LifeCycle arg0) {
			writeToTextPanel("机考服务地址发布器正在启动...", GREEN_ATT);	
			
		}

		@Override
		public void lifeCycleStopped(LifeCycle arg0) {
			examServerAddressSpeaker.setStarted(false);
			writeToTextPanel("机考服务地址发布器已停止", RED_ATT);
			statusJlabel.setIcon(new ImageIcon(getResource("resource/stop.png")));
			statusPanel.setToolTipText("已停止");
			publishButton.setEnabled(true);
			stopButton.setEnabled(false);
		}

		@Override
		public void lifeCycleStopping(LifeCycle arg0) {
			writeToTextPanel("机考服务地址发布器正在关闭...", RED_ATT);	
			
		}	
	}
    
    /**
     * 用于监听客户端访问情况的监听器
     * 
     * @author chz
     *
     */
    class HandlerListener implements IHandlerListener {

		@Override
		public void clientRequest(ReqEvent e) {
			String ip = e.getClientIP();
			int clientNum = e.getClientNum();
			writeToTextPanel("当前访问的客户端IP:" + ip + ", 总共收到：" + clientNum + "个客户端的访问。", BLACK_ATT);
			
		}
    	
    }
}

